... with gsk_opacity_node_new().
Also implement support for opacity in gtk_widget_snapshot() using this
new node.
GskRenderNodeType
gsk_render_node_get_node_type
gsk_render_node_draw
-gsk_render_node_set_opacity
GskBlendMode
gsk_render_node_set_blend_mode
GskScalingFilter
gsk_container_node_get_child
gsk_transform_node_new
gsk_transform_node_get_child
+gsk_opacity_node_new
+gsk_opacity_node_get_child
<SUBSECTION Standard>
GSK_IS_RENDER_NODE
GSK_RENDER_NODE
* @GSK_TEXTURE_NODE: A node drawing a #GskTexture
* @GSK_TRANSFORM_NODE: A node that renders its child after applying a
* matrix transform
+ * @GSK_OPACITY_NODE: A node that changes the opacity of its child
*
* The type of a node determines what the node is rendering.
*
GSK_CAIRO_NODE,
GSK_COLOR_NODE,
GSK_TEXTURE_NODE,
- GSK_TRANSFORM_NODE
+ GSK_TRANSFORM_NODE,
+ GSK_OPACITY_NODE
} GskRenderNodeType;
/**
static gboolean
render_node_needs_render_target (GskRenderNode *node)
{
- double opacity = gsk_render_node_get_opacity (node);
-
- if (opacity < 1.0)
- return TRUE;
-
return FALSE;
}
graphene_matrix_multiply (modelview, &self->mvp, &item.mvp);
item.z = project_item (projection, modelview);
- item.opacity = gsk_render_node_get_opacity (node);
+ item.opacity = 1.0;
item.blend_mode = gsk_render_node_get_blend_mode (node);
self->ref_count = 1;
- self->opacity = 1.0;
-
self->min_filter = GSK_SCALING_FILTER_NEAREST;
self->mag_filter = GSK_SCALING_FILTER_NEAREST;
node->node_class->get_bounds (node, bounds);
}
-/**
- * gsk_render_node_set_opacity:
- * @node: a #GskRenderNode
- * @opacity: the opacity of the node, between 0 (fully transparent) and
- * 1 (fully opaque)
- *
- * Sets the opacity of the @node.
- *
- * Since: 3.90
- */
-void
-gsk_render_node_set_opacity (GskRenderNode *node,
- double opacity)
-{
- g_return_if_fail (GSK_IS_RENDER_NODE (node));
- g_return_if_fail (node->is_mutable);
-
- node->opacity = CLAMP (opacity, 0.0, 1.0);
-}
-
-/**
- * gsk_render_node_get_opacity:
- * @node: a #GskRenderNode
- *
- * Retrieves the opacity set using gsk_render_node_set_opacity().
- *
- * Returns: the opacity of the #GskRenderNode
- *
- * Since: 3.90
- */
-double
-gsk_render_node_get_opacity (GskRenderNode *node)
-{
- g_return_val_if_fail (GSK_IS_RENDER_NODE (node), 0.0);
-
- return node->opacity;
-}
-
void
gsk_render_node_set_scaling_filters (GskRenderNode *node,
GskScalingFilter min_filter,
GskRenderNode * gsk_transform_node_get_child (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
-void gsk_render_node_set_opacity (GskRenderNode *node,
- double opacity);
+GskRenderNode * gsk_opacity_node_new (GskRenderNode *child,
+ double opacity);
+GDK_AVAILABLE_IN_3_90
+GskRenderNode * gsk_opacity_node_get_child (GskRenderNode *node);
GDK_AVAILABLE_IN_3_90
void gsk_render_node_set_blend_mode (GskRenderNode *node,
graphene_matrix_init_from_matrix (transform, &self->transform);
}
+/*** GSK_OPACITY_NODE ***/
+
+typedef struct _GskOpacityNode GskOpacityNode;
+
+struct _GskOpacityNode
+{
+ GskRenderNode render_node;
+
+ GskRenderNode *child;
+ double opacity;
+};
+
+static void
+gsk_opacity_node_finalize (GskRenderNode *node)
+{
+ GskOpacityNode *self = (GskOpacityNode *) node;
+
+ gsk_render_node_unref (self->child);
+}
+
+static void
+gsk_opacity_node_make_immutable (GskRenderNode *node)
+{
+ GskOpacityNode *self = (GskOpacityNode *) node;
+
+ gsk_render_node_make_immutable (self->child);
+}
+
+static void
+gsk_opacity_node_draw (GskRenderNode *node,
+ cairo_t *cr)
+{
+ GskOpacityNode *self = (GskOpacityNode *) node;
+ graphene_rect_t bounds;
+
+ cairo_save (cr);
+
+ /* clip so the push_group() creates a smaller surface */
+ gsk_render_node_get_bounds (self->child, &bounds);
+ cairo_rectangle (cr, bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
+ cairo_clip (cr);
+
+ cairo_push_group (cr);
+
+ gsk_render_node_draw (self->child, cr);
+
+ cairo_pop_group_to_source (cr);
+ cairo_paint_with_alpha (cr, self->opacity);
+
+ cairo_restore (cr);
+}
+
+static void
+gsk_opacity_node_get_bounds (GskRenderNode *node,
+ graphene_rect_t *bounds)
+{
+ GskOpacityNode *self = (GskOpacityNode *) node;
+
+ gsk_render_node_get_bounds (self->child, bounds);
+}
+
+static const GskRenderNodeClass GSK_OPACITY_NODE_CLASS = {
+ GSK_OPACITY_NODE,
+ sizeof (GskOpacityNode),
+ "GskOpacityNode",
+ gsk_opacity_node_finalize,
+ gsk_opacity_node_make_immutable,
+ gsk_opacity_node_draw,
+ gsk_opacity_node_get_bounds
+};
+
+/**
+ * gsk_opacity_node_new:
+ * @child: The node to draw
+ * @opacity: The opacity to apply
+ *
+ * Creates a #GskRenderNode that will drawn the @child with reduced
+ * @opacity.
+ *
+ * Returns: A new #GskRenderNode
+ *
+ * Since: 3.90
+ */
+GskRenderNode *
+gsk_opacity_node_new (GskRenderNode *child,
+ double opacity)
+{
+ GskOpacityNode *self;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
+
+ self = (GskOpacityNode *) gsk_render_node_new (&GSK_OPACITY_NODE_CLASS);
+
+ self->child = gsk_render_node_ref (child);
+ self->opacity = CLAMP (opacity, 0.0, 1.0);
+
+ return &self->render_node;
+}
+
+/**
+ * gsk_opacity_node_get_child:
+ * @node: a opacity @GskRenderNode
+ *
+ * Gets the child node that is getting opacityed by the given @node.
+ *
+ * Returns: (transfer none): The child that is getting opacityed
+ **/
+GskRenderNode *
+gsk_opacity_node_get_child (GskRenderNode *node)
+{
+ GskOpacityNode *self = (GskOpacityNode *) node;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_OPACITY_NODE), NULL);
+
+ return self->child;
+}
+
+double
+gsk_opacity_node_get_opacity (GskRenderNode *node)
+{
+ GskOpacityNode *self = (GskOpacityNode *) node;
+
+ g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_OPACITY_NODE), 1.0);
+
+ return self->opacity;
+}
+
void gsk_render_node_get_bounds (GskRenderNode *node,
graphene_rect_t *frame);
-double gsk_render_node_get_opacity (GskRenderNode *node);
+double gsk_opacity_node_get_opacity (GskRenderNode *node);
cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
.node = node
};
- if (gsk_render_node_get_opacity (node) < 1.0)
- goto fallback;
-
switch (gsk_render_node_get_node_type (node))
{
case GSK_NOT_A_RENDER_NODE:
break;
}
-
- return;
-
-fallback:
- g_array_append_val (self->render_ops, op);
}
void
GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (widget);
GdkWindow *event_window = NULL;
gboolean result;
- gboolean push_group;
RenderMode mode;
- push_group =
- widget->priv->alpha != 255 && !_gtk_widget_is_toplevel (widget);
-
- if (push_group)
- cairo_push_group (cr);
-
#ifdef G_ENABLE_CONSISTENCY_CHECKS
if (_gtk_widget_get_alloc_needed (widget))
g_warning ("%s %p is drawn without a current allocation. This should not happen.", G_OBJECT_TYPE_NAME (widget), widget);
}
else
{
+ gboolean push_group =
+ widget->priv->alpha != 255 && !_gtk_widget_is_toplevel (widget);
+
+ if (push_group)
+ cairo_push_group (cr);
+
if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
{
g_signal_emit (widget, widget_signals[DRAW],
GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr);
cairo_restore (cr);
}
+
+ if (push_group)
+ {
+ cairo_pop_group_to_source (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
+ }
}
#ifdef G_ENABLE_DEBUG
}
#endif
- if (push_group)
- {
- cairo_pop_group_to_source (cr);
- cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
- cairo_paint_with_alpha (cr, widget->priv->alpha / 255.0);
- }
-
if (cairo_status (cr) &&
event_window != NULL)
{
GtkAllocation clip;
GtkAllocation alloc;
RenderMode mode;
+ double opacity;
if (_gtk_widget_get_alloc_needed (widget))
return;
if (gtk_snapshot_clips_rect (snapshot, &bounds))
return;
+ if (_gtk_widget_is_toplevel (widget))
+ opacity = 1.0;
+ else
+ opacity = widget->priv->alpha / 255.0;
+ if (opacity <= 0.0)
+ return;
+
/* Compatibility mode: if the widget does not have a render node, we draw
* using gtk_widget_draw() on a temporary node
*/
}
else
{
+ if (opacity < 1.0)
+ gtk_snapshot_push (snapshot, TRUE, "OpacityGroup<%s>", G_OBJECT_TYPE_NAME (widget));
+
+ klass->snapshot (widget, snapshot);
+
if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
{
/* Compatibility mode: if there's a ::draw signal handler, we add a
gboolean result;
cairo_t *cr;
- klass->snapshot (widget, snapshot);
-
cr = gtk_snapshot_append_cairo_node (snapshot,
&bounds,
"DrawSignalContents<%s>", G_OBJECT_TYPE_NAME (widget));
g_signal_emit (widget, widget_signals[DRAW], 0, cr, &result);
cairo_destroy (cr);
}
- else
+
+ if (opacity < 1.0)
{
- klass->snapshot (widget, snapshot);
+ GskRenderNode *opacity_node, *node;
+
+ node = gtk_snapshot_pop (snapshot);
+ opacity_node = gsk_opacity_node_new (node, opacity);
+ gsk_render_node_set_name (opacity_node, "Opacity");
+ gsk_render_node_unref (node);
+
+ gtk_snapshot_append_node (snapshot, opacity_node);
+ gsk_render_node_unref (opacity_node);
}
}
}
append_node (nodemodel, gsk_transform_node_get_child (node), priv->nodes->len - 1);
break;
+ case GSK_OPACITY_NODE:
+ append_node (nodemodel, gsk_opacity_node_get_child (node), priv->nodes->len - 1);
+ break;
+
case GSK_CONTAINER_NODE:
{
gint elt_index;
-1);
g_free (tmp);
- tmp = g_strdup_printf ("%.2f", gsk_render_node_get_opacity (node));
- gtk_list_store_insert_with_values (store, NULL, -1,
- 0, "Opacity",
- 1, tmp,
- -1);
- g_free (tmp);
-
gtk_list_store_insert_with_values (store, NULL, -1,
0, "Has Surface",
1, gsk_render_node_get_node_type (node) == GSK_CAIRO_NODE ? "TRUE" : "FALSE",